using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JoyfulHomeJourney.BackEnd.Infrastructure.Atrributes;
using JoyfulHomeJourney.BackEnd.Infrastructure.Dtos.Requests.Objects;
using JoyfulHomeJourney.BackEnd.Infrastructure.Dtos.Responses;
using JoyfulHomeJourney.BackEnd.Infrastructure.Dtos.Responses.Objects;
using JoyfulHomeJourney.BackEnd.Infrastructure.EFCore;
using JoyfulHomeJourney.BackEnd.Infrastructure.Tools;
using JoyfulHomeJourney.BackEnd.Server.EFCore;
using JoyfulHomeJourney.BackEnd.Server.Instances.Extends.Requests;
using JoyfulHomeJourney.BackEnd.Server.Instances.Extends.Responses;
using JoyfulHomeJourney.BackEnd.Server.Interfaces;
using Microsoft.EntityFrameworkCore;
namespace JoyfulHomeJourney.BackEnd.Server.Instances
{
    /// <summary>
    /// 一个类包含了服务类所需的所有仓库表的实例，仅提供给该服务类使用，请将所有服务类所需的仓库表的实例都放在该类中。
    /// 仓库表的实例指提供了操作数据库指定表的所有方法的对象
    /// </summary>
    internal class SysCarSuppliesEF
    {
        public SysCarSuppliesEF(DbContext dbContext)
        {
            sysCarSuppliesServerEF = new SysCarSuppliesServerEF(dbContext);
            sysProductsServerEF = new SysProductsServerEF(dbContext);
            dictionarysServerEF = new DictionarysServerEF(dbContext);
            sysAdminsServerEF = new SysAccountsServerEF(dbContext);
        }
        public SysCarSuppliesServerEF sysCarSuppliesServerEF { get; set; }
        public SysProductsServerEF sysProductsServerEF { get; set; }
        public DictionarysServerEF dictionarysServerEF { get; set; }
        public SysAccountsServerEF sysAdminsServerEF { get; set; }
    }
    [InjectClass]
    public class SysCarSuppliesServer : ISysCarSuppliesServer
    {
        private readonly SysCarSuppliesEF _sysCarSuppliesEF;//包含所有所需仓库表实现的对象
                                                            // 请不要修改该构造方法,也无需添加属性，而应该在上面的EF类中添加属性和构造函数赋值语句
        public SysCarSuppliesServer(DbContext dbContext)
        {
            _sysCarSuppliesEF = new SysCarSuppliesEF(dbContext);
        }
        private string AddValidator(RequestSysCarSuppliesDto dto)
        {
            if (dto.imageFileList.Count > 10)
            {
                return "最多只能上传十张图片";
            }
            if (dto.deduction > dto.price * dto.discount / 100)
            {
                return "抵扣金额不能大于等于价格折扣后的金额";
            }
            return null;
        }
        public async Task<ResponseApiDto> AddAsync(RequestSysCarSuppliesDto dto, string aid)
        {
            string validatedResult = AddValidator(dto);
            if (validatedResult != null)
            {
                ResponseApiDto.Fail(validatedResult);
            }
            int affectedRows = 0;
            List<string> newImagePaths = new List<string>();
            await _sysCarSuppliesEF.sysCarSuppliesServerEF.ExecuteInTransactionAsync(async () =>
            {
                // 图片路径中的id是carSuppliesId即便图片字段属于product,否则需要productId传回前端
                string id = Tools.Guid_2();
                string imageP = "";
                // 上传图片
                foreach (var image in dto.imageFileList)
                {
                    string temp = await Tools.UploadImage(image, Path.Combine(Tools.GetImageCarSuppliesPath(), id));
                    imageP += temp + ",";
                    newImagePaths.Add(Path.Combine(Tools.GetImageCarSuppliesPath(), id, temp));
                }
                // 添加产品表
                var product = dto.ToSysProductsCreateEntity();
                product.PCategory = "sys_car_supplies";
                product.PImages = imageP.Substring(0, imageP.Length - 1);
                affectedRows += await _sysCarSuppliesEF.sysProductsServerEF.AddAsync(product);
                // 添加汽车用品表
                var carSupplies = dto.ToCreateEntity();
                carSupplies.CsProductId = product.PId;
                carSupplies.CsCreateMan = aid;
                affectedRows += await _sysCarSuppliesEF.sysCarSuppliesServerEF.AddAsync(carSupplies, id);
            }, () =>
            {
                affectedRows = 0;
                // 删除图片
                foreach (var imagePath in newImagePaths)
                {
                    Tools.DeleteImage(imagePath);
                }
                // 删除文件夹
                Tools.DeleteDirectory(Path.GetDirectoryName(newImagePaths[0]));
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }
        // 不带文件的添加
        public async Task<ResponseApiDto> AddAsync2(RequestSysCarSuppliesDto dto, string aid)
        {
            int affectedRows = 0;
            string id = Tools.Guid_1();
            await _sysCarSuppliesEF.sysCarSuppliesServerEF.ExecuteInTransactionAsync(async () =>
             {
                 // 添加产品表
                 var product = dto.ToSysProductsCreateEntity();
                 product.PCategory = "sys_car_supplies";
                 product.PImages = "";
                 affectedRows += await _sysCarSuppliesEF.sysProductsServerEF.AddAsync(product,id);
                 // 添加汽车用品表
                 var carSupplies = dto.ToCreateEntity();
                 carSupplies.CsProductId = product.PId;
                 carSupplies.CsCreateMan = aid;
                 affectedRows += await _sysCarSuppliesEF.sysCarSuppliesServerEF.AddAsync(carSupplies);
             }, () => { affectedRows = 0; return null; });
            return ResponseApiDto.Create(affectedRows, data: affectedRows > 0 ? id : null);
        }
        private async Task<bool> Exist(string id)
        {
            return await _sysCarSuppliesEF.sysCarSuppliesServerEF.Query(d => d.CsId == id).AnyAsync();
        }
        public async Task<ResponseApiDto> DeleteAsync(RequestSysCarSuppliesDto dto)
        {
            if (!await Exist(dto.id))
            {
                return ResponseApiDto.Fail("该汽车用品不存在");
            }
            int affectedRows = 0;
            List<FileInfo> deletedImages = new List<FileInfo>();// 删除的图片文件
            await _sysCarSuppliesEF.sysCarSuppliesServerEF.ExecuteInTransactionAsync(async () =>
            {
                // 删除汽车表
                string productId = await _sysCarSuppliesEF.sysCarSuppliesServerEF.Query(d => d.CsId == dto.id).Select(d => d.CsProductId).SingleOrDefaultAsync();
                SysCarSupplies carSupplies = new SysCarSupplies { CsId = dto.id };
                affectedRows += await _sysCarSuppliesEF.sysCarSuppliesServerEF.DeleteAsync(carSupplies);
                // 删除产品表
                SysProducts product = new SysProducts { PId = productId };
                // 从数据库查询图片名称，并删除
                var oldImageNames = await _sysCarSuppliesEF.sysProductsServerEF.Query(d => d.PId == productId).Select(d => d.PImages).SingleAsync();
                foreach (var image in oldImageNames.Split(','))
                {
                    FileInfo file = new FileInfo(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, image));
                    deletedImages.Add(file);
                    Tools.DeleteImage(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, image));
                }
                Tools.DeleteDirectory(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id));
                affectedRows += await _sysCarSuppliesEF.sysProductsServerEF.DeleteAsync(product);
            }, () =>
            {
                affectedRows = 0;
                // 恢复图片
                foreach (var deletedImage in deletedImages)
                {
                    deletedImage.CopyTo(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, deletedImage.Name), overwrite: true);
                }
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }
        public async Task<ResponseApiDto> UpdateAsync(RequestSysCarSuppliesDto dto)
        {
            if (!await Exist(dto.id))
            {
                return ResponseApiDto.Fail("该汽车用品不存在");
            }
            if (dto.imageOrders.Count > 10)
            {
                return ResponseApiDto.Fail("最多只能上传十张图片");
            }
            var affectedRows = 0;
            List<string> createdImagePaths = new List<string>();// 新增的图片的位置
            List<FileInfo> deletedImages = new List<FileInfo>();// 删除的图片文件
            await _sysCarSuppliesEF.sysCarSuppliesServerEF.ExecuteInTransactionAsync(async () =>
            {
                string newImageNames = "";// 新的图片名集合字符串
                List<string> imagesNames = dto.imageFileList?.Select(d => d.FileName).ToList() ?? new List<string>();// 要新增的图片名称列表
                // 新增图片
                foreach (var item in dto.imageOrders)
                {
                    if (imagesNames.Contains(item))
                    {
                        var image = dto.imageFileList.Where(d => d.FileName == item).SingleOrDefault();
                        string newImageName = await Tools.UploadImage(image, Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id));
                        newImageNames += newImageName + ",";
                        createdImagePaths.Add(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, newImageName));
                    }
                    else if (dto.retainImages?.Contains(item) ?? false)
                    {
                        newImageNames += item + ",";
                    }
                }
                // 比对数据库的数据并删除不保留的图片
                var productId = await _sysCarSuppliesEF.sysCarSuppliesServerEF.Query(d => d.CsId == dto.id).Select(d => d.CsProductId).SingleAsync();
                var oldImageNames = await _sysCarSuppliesEF.sysProductsServerEF.Query(d => d.PId == productId).Select(d => d.PImages).SingleAsync();
                foreach (var oldImageName in oldImageNames.Split(",").ToList())
                {
                    if (!(dto.retainImages?.Contains(oldImageName) ?? false))
                    {
                        FileInfo file = new FileInfo(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, oldImageName));
                        deletedImages.Add(file);
                        Tools.DeleteImage(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, oldImageName));
                    }
                }
                // 修改汽车表
                var carSupplies = dto.ToCreateEntity();
                affectedRows += await _sysCarSuppliesEF.sysCarSuppliesServerEF.UpdateAllProperNotNullAsync(carSupplies);
                // 修改产品表
                var product = dto.ToSysProductsCreateEntity();
                product.PId = productId;
                affectedRows += await _sysCarSuppliesEF.sysProductsServerEF.UpdateAllProperNotNullAsync(product);
            }, () =>
            {
                affectedRows = 0;
                // 删除图片
                foreach (var imagePath in createdImagePaths)
                {
                    Tools.DeleteImage(imagePath);
                }
                // 恢复图片
                foreach (var deletedImage in deletedImages)
                {
                    deletedImage.CopyTo(Path.Combine(Tools.GetImageCarSuppliesPath(), dto.id, deletedImage.Name), overwrite: true);
                }
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }
        public async Task<ResponseApiDto> Detail(string id)
        {
            var carSupplies = (await _sysCarSuppliesEF.sysCarSuppliesServerEF.Query(d => d.CsId == id).SingleOrDefaultAsync());
            var product = await _sysCarSuppliesEF.sysProductsServerEF.Query(d => d.PId == carSupplies.CsProductId).SingleOrDefaultAsync();
            var carSuppliesResponse = carSupplies.ToResponseDto(product);
            carSuppliesResponse.categoryName = await _sysCarSuppliesEF.dictionarysServerEF.Query(d => d.DId == carSuppliesResponse.brand).Select(d => d.DValue).SingleOrDefaultAsync();
            carSuppliesResponse.brandName = await _sysCarSuppliesEF.dictionarysServerEF.Query(d => d.DId == product.PBrand).Select(d => d.DValue).SingleOrDefaultAsync();
            carSuppliesResponse.createManName = await _sysCarSuppliesEF.sysAdminsServerEF.Query(d => d.AId == carSuppliesResponse.createMan).Select(d => d.AName).SingleOrDefaultAsync();
            return ResponseApiDto.Success("数据已获取", carSuppliesResponse);
        }

        public async Task<ResponseApiDto> PaginationAsync(int page, int limit, string key, string shopId, string field, bool? order)
        {
            int total = 0;
            List<ResponseSysCarSuppliesDto> data = new List<ResponseSysCarSuppliesDto>();
            var iq = orderByField(_sysCarSuppliesEF.sysCarSuppliesServerEF.Query(d => d.CsProduct.PCsId == shopId && (key == null || d.CsProduct.PName.Contains(key))), field, order ?? true);
            total = await iq.CountAsync();
            List<SysCarSupplies> sysCarSuppliess = await iq.Skip((page - 1) * limit).Take(limit).ToListAsync();
            foreach (var sysCarSupplies in sysCarSuppliess)
            {
                var product = await _sysCarSuppliesEF.sysProductsServerEF.Query(d => d.PId == sysCarSupplies.CsProductId).SingleOrDefaultAsync();
                var carSupplies = sysCarSupplies.ToResponseDto(product);
                carSupplies.categoryName = await _sysCarSuppliesEF.dictionarysServerEF.Query(d => d.DId == sysCarSupplies.CsCategory).Select(d => d.DValue).SingleOrDefaultAsync();
                carSupplies.brandName = await _sysCarSuppliesEF.dictionarysServerEF.Query(d => d.DId == product.PBrand).Select(d => d.DValue).SingleOrDefaultAsync();
                carSupplies.createManName = await _sysCarSuppliesEF.sysAdminsServerEF.Query(d => d.AId == sysCarSupplies.CsCreateMan).Select(d => d.AName).SingleOrDefaultAsync();
                data.Add(carSupplies);
            }
            return ResponseApiDto.Success("数据已获取", new ResponsePaginationDto { total = total, data = data });
        }
        private IQueryable<SysCarSupplies> orderByField(IQueryable<SysCarSupplies> iq, string field, bool isAsc)
        {
            switch (field)
            {
                case "name":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PName);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PName);
                    }
                    break;
                case "brandName":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PBrandNavigation.DValue);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PBrandNavigation.DValue);
                    }
                    break;
                case "categoryName":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsCategoryNavigation.DValue);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsCategoryNavigation.DValue);
                    }
                    break;
                case "price":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PPrice);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PPrice);
                    }
                    break;
                case "discount":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PDiscount);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PDiscount);
                    }
                    break;
                case "deduction":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PDeduction);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PDeduction);
                    }
                    break;
                case "color":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsColor);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsColor);
                    }
                    break;
                case "dimension":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsDimension);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsDimension);
                    }
                    break;
                case "weight":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsWeight);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsWeight);
                    }
                    break;
                case "saleCount":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PSaleCount);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PSaleCount);
                    }
                    break;
                case "markUp":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsMarkUp);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsMarkUp);
                    }
                    break;
                case "createManName":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsCreateManNavigation.AName);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsCreateManNavigation.AName);
                    }
                    break;
                case "createAt":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PCreateAt);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PCreateAt);
                    }
                    break;
                case "updateAt":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PUpdateAt);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PUpdateAt);
                    }
                    break;
                default:
                    iq = iq.OrderByDescending(d => d.CsProduct.PCreateAt);
                    break;
            }
            return iq;
        }
    }
}
